using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Universal.Application.Common;
using Universal.Application.Contracts.Common;
using Universal.Application.Contracts.Dto.Auth;
using Universal.Application.Contracts.Jwt;
using Universal.Application.Repositories;
using Universal.Domain.Entities.App;
using Universal.Domain.Events;
using Universal.Domain.Repositories;

namespace Universal.Application.Services;

/// <summary>
/// 登录注册服务
/// </summary>
public class AuthService : IAuthService
{
    private readonly IRepository<AppUser> _userRepository;
    private readonly IJwtTokenService _jwtTokenService;
    private readonly ILogService _logService;
    private readonly IDomainEventDispatcher _domainEventDispatcher;

    public AuthService(IRepository<AppUser> userRepository, IJwtTokenService jwtTokenService, ILogService logService, IDomainEventDispatcher domainEventDispatcher)
    {
        _userRepository = userRepository;
        _jwtTokenService = jwtTokenService;
        _logService = logService;
        _domainEventDispatcher = domainEventDispatcher;
    }

    public async Task<dynamic> LoginAsync(LoginDto loginDto)
    {
        if (string.IsNullOrWhiteSpace(loginDto.Username) || string.IsNullOrWhiteSpace(loginDto.Password))
        {
            return ApiResponse<string>.Failure(5001, "用户名和密码不能为空");
        }

        // 查询用户（包含角色）
        var user = (await _userRepository.Query()
            .Include(u => u.Roles)
            .Where(x => x.Username == loginDto.Username)
            .ToListAsync())
            .FirstOrDefault();

        if (user == null)
        {
            await _logService.WriteLogAsync($"用户名不存在，请确认后重试!!");
            return ApiResponse<string>.Failure(5002, "用户名不存在，请确认后重试!!");
        }

        if (user.IsActive == false)
        {
            await _logService.WriteLogAsync($"用户已禁用，请联系管理员!!");
            return ApiResponse<string>.Failure(5003, "用户已禁用，请联系管理员!!");
        }

        if (user.AccountLockedUntil.HasValue && user.AccountLockedUntil.Value > DateTime.UtcNow)
        {
            await _logService.WriteLogAsync($"用户{loginDto.Username}尝试登录，但账户已锁定至{user.AccountLockedUntil.Value:yyyy-MM-dd HH:mm:ss}");
            return ApiResponse<string>.Failure(5004, $"账户已锁定至{user.AccountLockedUntil.Value:yyyy-MM-dd HH:mm:ss}");
        }

        if (!PasswordHasher.VerifyPassword(loginDto.Password, user.Password))
        {
            user.LoginAttempts++;
            if (user.LoginAttempts >= 5)
            {
                user.AccountLockedUntil = DateTime.UtcNow.AddMinutes(30);
                user.LoginAttempts = 0;
            }
            await _userRepository.UpdateAsync(user);
            return ApiResponse<string>.Failure(5005, "用户名或密码错误，请确认后重试!!");
        }

        user.LoginAttempts = 0;
        user.AccountLockedUntil = null;

        // 生成Token - 使用配置中的过期时间
        var token = _jwtTokenService.GenerateToken(user.Id, user.Username);

        // 生成RefreshToken
        var refreshToken = Guid.NewGuid().ToString("N");
        var refreshTokenExpiry = DateTime.UtcNow.AddDays(7); // 7天有效期
        user.RefreshToken = refreshToken;
        user.RefreshTokenExpiry = refreshTokenExpiry;
        await _userRepository.UpdateAsync(user);

        // 组装用户信息
        var userInfo = new UserInfoDto
        {
            Id = user.Id,
            Username = user.Username,
            Email = user.Email,
            Avatar = user.Avatar,
            Roles = user.Roles.Select(r => r.Rolename)
        };

        var result = new LoginResultDto(userInfo, token, refreshToken, 7200);

        return ApiResponse<LoginResultDto>.Success(result, "登录成功");
    }

    /// <summary>
    /// 刷新令牌
    /// </summary>
    public async Task<dynamic> RefreshTokenAsync(RefreshTokenRequestDto refreshTokenRequestDto)
    {
        // 1. 校验 refresh token 是否存在
        var user = (await _userRepository.GetAllAsync())
            .FirstOrDefault(u => u.RefreshToken == refreshTokenRequestDto.RefreshToken);

        if (user == null || user.RefreshTokenExpiry == null || user.RefreshTokenExpiry < DateTime.UtcNow)
        {
            return ApiResponse<RefreshTokenResponseDto>.Failure(4001, "RefreshToken无效或已过期");
        }

        // 2. 生成新的 access token 和 refresh token
        var newAccessToken = _jwtTokenService.GenerateToken(user.Id, user.Username);
        var newRefreshToken = Guid.NewGuid().ToString("N");
        var refreshTokenExpiresAt = DateTime.UtcNow.AddDays(7);

        // 3. 更新用户 refresh token
        user.RefreshToken = newRefreshToken;
        user.RefreshTokenExpiry = refreshTokenExpiresAt;
        await _userRepository.UpdateAsync(user);

        var response = new RefreshTokenResponseDto(newAccessToken, newRefreshToken, 7200);


        return ApiResponse<RefreshTokenResponseDto>.Success(response, "刷新成功");

    }

    /// <summary>
    /// 注册用户
    /// </summary>
    public async Task<dynamic> RegisterAsync(RegisterDto registerDto)
    {
        var existingUser = await _userRepository.GetAllAsync();
        if (existingUser.Any(x => x.Username == registerDto.Username))
        {
            // _logger.LogError("用户名已存在,请重新输入!!");
            return ApiResponse<string>.Failure(5001, "用户名已存在,请重新输入!!");
        }

        // 加密密码
        var hashedPassword = PasswordHasher.HashPassword(registerDto.Password);

        var user = new AppUser
        {
            Username = registerDto.Username,
            Password = hashedPassword,
            Email = registerDto.Email,
        };

        await _userRepository.AddAsync(user);

        // 颁发领域事件
        user.Register();

        await _domainEventDispatcher.DispatchAsync(user.DomainEvents);

        // 清空事件，防止重复分发
        user.ClearDomainEvents();

        return ApiResponse<string>.Success("注册成功");
    }

}